﻿package com.Galaxisfarm {
	// Bibliotecas da game engine Flixel
	import com.adamatomic.flixel.*;
	// Bibliotecas para usar Lua	
	import luaAlchemy.LuaAlchemy;
    import luaAlchemy.lua_wrapper;
	import cmodule.lua_wrapper.CLibInit;
    import flash.utils.ByteArray;
	
	public class PhaseState extends GameState {
		// Arquivo de utilitários do Lua para o jogo
		[Embed(source = "../../data/lua/utils.lua", mimeType = "application/octet-stream")] private var _lua_utils_class:Class;
		// Arquivo Lua da primeira fase
		[Embed(source = "../../data/lua/phase_one.lua", mimeType = "application/octet-stream")] private var _lua_phase_one_class:Class;
		// Arquivo Lua da segunda fase
		[Embed(source = "../../data/lua/phase_two.lua", mimeType = "application/octet-stream")] private var _lua_phase_two_class:Class;
		// Arquivo Lua da terceira fase
		[Embed(source = "../../data/lua/phase_three.lua", mimeType = "application/octet-stream")] private var _lua_phase_three_class:Class;
		// Arquivo Lua da quarta fase
		[Embed(source = "../../data/lua/phase_fourth.lua", mimeType = "application/octet-stream")] private var _lua_phase_fourth_class:Class;
		// Arquivo Lua da quinta fase
		[Embed(source = "../../data/lua/phase_fifth.lua", mimeType = "application/octet-stream")] private var _lua_phase_fifth_class:Class;
		// Sprite do rio da Amazônia
		[Embed(source = "../../data/river_amazonia.png")] protected var ImgRiverAmazonia:Class;
		// Sprite do rio do Cerrado
		[Embed(source = "../../data/river_cerrado.png")] protected var ImgRiverCerrado:Class;
		// Sprite do rio da Mata Atlântica
		[Embed(source = "../../data/river_mata_atlantica.png")] protected var ImgRiverMataAtlantica:Class;
		// Sprite do celeiro
		[Embed(source = "../../data/cowshed.png")] protected var ImgCowshed:Class;
		// Sprite do curral
		[Embed(source = "../../data/freestall.png")] protected var ImgFreestall:Class;
		// Sprite da esterqueira
		[Embed(source = "../../data/midden.png")] protected var ImgMidden:Class;
		
		// Variável de estado da máquina virtual do Lua
		protected var _lua_state:uint;
		// Variável da máquina virtual do Lua
		protected static var _lua:LuaAlchemy;
		// Variável que contém todos os arquivos Lua disponíveis
		protected var _lua_embedded_files:Array = [
			{ path: "utils.lua", asset: _lua_utils_class },
			{ path: "phase_one.lua", asset: _lua_phase_one_class },
			{ path: "phase_two.lua", asset: _lua_phase_two_class },
			{ path: "phase_three.lua", asset: _lua_phase_three_class },
			{ path: "phase_fourth.lua", asset: _lua_phase_fourth_class },
			{ path: "phase_fifth.lua", asset: _lua_phase_fifth_class }
		];
		// Variável que armazena a porcentagem da reserva legal
		protected var _percentage_legal_reserve:Number;
		// Variável que armazena o botão para adicionar o celeiro
		protected var _button_add_cowshed:FlxButton;
		// Variável que armazena o botão para adicionar o curral
		protected var _button_add_freestall:FlxButton;
		// Variável que armazena o botão para adicionar a esterqueira
		protected var _button_add_midden:FlxButton;
		// Variável que armazena o painel de ação
		protected var _action_panel:ActionPanel;
		// Variável que armazena o preço do celeiro
		protected var _cowshed_price:Number;
		// Variável que armazena o preço do curral
		protected var _freestall_price:Number;
		// Variável que armazena o preço da esterqueira
		protected var _midden_price:Number;
		// Variável que armazena o celeiro
		protected var _cowshed:Cowshed;
		// Borda do celeiro selecionado
		protected static var _cowshed_selected:FlxSprite;
		// Variável que armazena o curral
		protected var _freestall:Freestall;
		// Borda do curral selecionado
		protected static var _freestall_selected:FlxSprite;
		// Variável que armazena a esterqueira
		protected var _midden:Midden;
		// Borda da esterqueira selecionada
		protected static var _midden_selected:FlxSprite;
		// Sprite do rio da Amazônia
		protected var _river_amazonia:FlxSprite;
		// Sprite do rio do Cerrado
		protected var _river_cerrado:FlxSprite;
		// Sprite do rio da Mata Atlântica
		protected var _river_mata_atlantica:FlxSprite;
		// Hud
		protected var _hud:Hud = null;
		// Armazena o jogador
		protected var _player:Player = null;
		
		// Método construtor
		public function PhaseState():void {
			// Chama o construtor da classe herdada
			super();
			
			_hud = null;
			_river_amazonia = null;
			_river_cerrado = null;
			_river_mata_atlantica = null;
			
			// Inicialmente o botão para o adicionar o celeiro
			// é definido como nulo
			_button_add_cowshed = null;
			
			// Inicialmente o painel de ação
			// é definido como nulo
			_action_panel = null;
			
			// Inicialmente o celeiro
			// é definido como nulo
			_cowshed = null;
			
			// Roda os scripts em Lua
			runLua();
			
			// Roda o script lua da primeira fase
			runScriptLua("utils.lua");
		}
		
		// Método chamado constantemente
		override public function update():void {
			super.update();
			
			// Atualiza o dinheiro
			if (_hud != null)
				_hud.setMoney(Farm.getMoney());
			
			// Para o tempo se estiver sendo exibida uma dialog box
			if (!hasDialogBox()) {
				// Atualiza o tempo
				Farm.setTime(Farm.getTime() - FlxG.elapsed);
				if (_hud != null) {
					_hud.setTime(Farm.getTime());
					_hud.runClock();
				}
			} else {
				if (_hud != null)
					_hud.stopClock();
			}
			
			// Se o tempo for menor ou igual a zero
			// dá game over
			if (Farm.getTime() <= 0) {
				FlxG.switchState(GameOverState);
			}
		}
		
		// Método que define o preço da esterqueira
		public function setMiddenPrice(Value:Number):void {
			_midden_price = Value;
		}
		
		// Método que obtém o preço da esterqueira
		public function getMiddenPrice():Number {
			return _midden_price;
		}
		
		// Método que define o preço do curral
		public function setFreestallPrice(Value:Number):void {
			_freestall_price = Value;
		}
		
		// Método que obtém o preço do curral
		public function getFreestallPrice():Number {
			return _freestall_price;
		}
		
		// Método que define o preço do celeiro
		public function setCowshedPrice(Value:Number):void {
			_cowshed_price = Value;
		}
		
		// Método que obtém o preço do celeiro
		public function getCowshedPrice():Number {
			return _cowshed_price;
		}

		// Método que define o tempo
		public function setTime(Value:Number):void {
			Farm.setTime(Value);
		}
		
		// Método que define o dinheiro
		public function setMoney(Value:int):void {
			Farm.setMoney(Value);
		}
		
		// Cria a hud
		public function createHud(X:uint, Y:uint):void {
			_hud = new Hud(X, Y);
		}
		
		// Cria o action panel
		public function createActionPanel(X:uint, Y:uint):void {
			_action_panel = new ActionPanel(X, Y);
			_lyr_sprites.add(_action_panel);
		}
		
		// Cria o botão para corta as árvores
		public function createButtonCutTree(X:uint, Y:uint):void {
			var buttonCutTree:ButtonCutTree = new ButtonCutTree(this, X, Y);
			_lyr_sprites.add(buttonCutTree);
		}
		
		// Cria o botão para adicionar o celeiro
		public function createButtonAddCowshed(X:uint, Y:uint):void {
			_button_add_cowshed = new ButtonAddCowshed(this, X, Y);
			_lyr_sprites.add(_button_add_cowshed);
		}
		
		// Cria o botão para adicionar o curral
		public function createButtonAddFreestall(X:uint, Y:uint):void {
			_button_add_freestall = new ButtonAddFreestall(this, X, Y);
			_lyr_sprites.add(_button_add_freestall);
		}
		
		// Cria o botão para adicionar a esterqueira
		public function createButtonAddMidden(X:uint, Y:uint):void {
			_button_add_midden = new ButtonAddMidden(this, X, Y);
			_lyr_sprites.add(_button_add_midden);
		}

		// Cria o sprite de colisão do rio
		public function createRiverAmazonia():void {
			_river_amazonia = new FlxSprite(ImgRiverAmazonia, 20, 0, false, false, 259, 400);
			_river_amazonia.visible = false;
			_lyr_sprites.add(_river_amazonia);
		}
		
		// Cria o sprite de colisão do rio
		public function createRiverMataAtlantica():void {
			_river_mata_atlantica = new FlxSprite(ImgRiverMataAtlantica, 356, 225, false, false, 304, 175);
			_river_mata_atlantica.visible = false;
			_lyr_sprites.add(_river_mata_atlantica);
		}
		
		// Cria o sprite de colisão do rio
		public function createRiverCerrado():void {
			_river_cerrado = new FlxSprite(ImgRiverCerrado, 20, 247, false, false, 399, 153);
			_river_cerrado.visible = false;
			_lyr_sprites.add(_river_cerrado);
		}
		
		// Cria o background da Amazônia
		public function createBackgroundAmazonia():void {
			// Adiciona o background no palco
			var background:BackgroundAmazonia = new BackgroundAmazonia(20, 20);
			background.play("animate");
			_lyr_stage.add(background);
		}
		
		// Cria o background do Cerrado
		public function createBackgroundCerrado():void {
			// Adiciona o background no palco
			var background:BackgroundCerrado = new BackgroundCerrado(20, 20);
			background.play("animate");
			_lyr_stage.add(background);
		}
		
		// Cria o background da Mata Atlântica
		public function createBackgroundMataAtlantica():void {
			// Adiciona o background no palco
			var background:BackgroundMataAtlantica = new BackgroundMataAtlantica(20, 20);
			background.play("animate");
			_lyr_stage.add(background);
		}
		
		// Cria o jogador e deixa oculto
		public function createPlayerHidden():void {
			_player = new Player(20, 0);
			_player.visible = false;
			_lyr_sprites.add(_player);
		}
		
		// Cria o celeiro e deixa oculto
		// isso é para forçar ele sempre
		// ficar atrás da hud
		public function createCowshedHidden():void {
			_cowshed = new Cowshed(20, 20);
			_cowshed.visible = false;
			_lyr_sprites.add(_cowshed);
		}
		
		// Cria o curral e deixa oculto
		// isso é para forçar ele sempre
		// ficar atrás da hud
		public function createFreestallHidden():void {
			_freestall = new Freestall(20, 20);
			_freestall.visible = false;
			_lyr_sprites.add(_freestall);
		}
		
		// Cria a esterqueira e deixa oculto
		// isso é para forçar ele sempre
		// ficar atrás da hud
		public function createMiddenHidden():void {
			_midden = new Midden(20, 20);
			_midden.visible = false;
			_lyr_sprites.add(_midden);
		}
		
		// Método que roda os arquivos lua
		protected function runLua():void {
			const libInitializer:CLibInit = new CLibInit();
			var luaFile:Object;
			
			// Carrega cada um dos arquivos em Lua
			for each (luaFile in _lua_embedded_files) {
				var luaAsset:ByteArray = new luaFile.asset() as ByteArray;
				libInitializer.supplyFile(luaFile.path, luaAsset);
			}
			
			// Inicializa o estado do Lua
			_lua_state = lua_wrapper.luaInitilizeState();
			// Passa a classe atual para o Lua
			lua_wrapper.setGlobal(_lua_state, "theState", this);
			// Disponibiliza a região como variável
			lua_wrapper.setGlobalLuaValue(_lua_state, "region", RegionState.getRegion());
		}
		
		// Método que executa um script lua
		protected function runScriptLua(script:String):void {
			// Executa os utilitários, que servem para facilitar a chamada aos métodos.
			var stack:Array = lua_wrapper.doFile(_lua_state, script);
			// Verifica erros
			checkErrorsLua(stack);			
		}
		
		// Verifica os erros do lua
		protected function checkErrorsLua(stack:Array):void {
			if (stack.shift() == false) {
				trace("Lua erro: " + stack.join("\n"));
			}
		}
		
		// Método que obtém a porcentagem da reserva legal
		public function getPercentageLegalReserva():Number {
			return _percentage_legal_reserve;
		}
		
		// Método que define a porcentagem da reserva legal
		public function setPercentageLegalReserve(Value:Number):void {
			_percentage_legal_reserve = Value;
		}
		
		// Método que adiciona as árvores
		public function addTrees():void {
			// Cria as árvores
			var trees:FlxArray = Farm.getTrees();
			for (var i:int = 0; i < trees.length; i++) {
				_lyr_sprites.add(trees[i]);
			}
		}
		
		// Método que adiciona o celeiro
		public function addCowshed():void {
			_cowshed = Farm.getCowshed();
			_lyr_sprites.add(_cowshed);
		}
		
		// Método que adiciona o celeiro selecionado
		public function addCowshedSelected():void {
			if (_cowshed) {
				_cowshed_selected = new FlxSprite(ImgCowshed, _cowshed.x, _cowshed.y, false, false, 143, 123);
				_cowshed_selected.addAnimation("selected", [1]);
				_cowshed_selected.play("selected");
				_cowshed_selected.visible = false;
				_lyr_sprites.add(_cowshed_selected);
			}
		}
		
		// Método que adiciona o curral selecionado
		public function addFreestallSelected():void {
			if (_freestall) {
				_freestall_selected = new FlxSprite(ImgFreestall, _freestall.x, _freestall.y, false, false, 172, 118);
				_freestall_selected.addAnimation("selected", [4]);
				_freestall_selected.play("selected");
				_freestall_selected.visible = false;
				_lyr_sprites.add(_freestall_selected);
			}
		}
		
		// Método que adiciona a esterqueira selecionado
		public function addMiddenSelected():void {
			if (_midden) {
				_midden_selected = new FlxSprite(ImgMidden, _midden.x, _midden.y, false, false, 86, 52);
				_midden_selected.addAnimation("selected", [14]);
				_midden_selected.play("selected");
				_midden_selected.visible = false;
				_lyr_sprites.add(_midden_selected);
			}
		}
		
		// Sprite do celeiro selecionado
		public static function getCowshedSelected():FlxSprite {
			return _cowshed_selected;
		}
		
		// Sprite do curral selecionado
		public static function getFreestallSelected():FlxSprite {
			return _freestall_selected;
		}
		
		// Sprite da esterqueira selecionado
		public static function getMiddenSelected():FlxSprite {
			return _midden_selected;
		}
		
		// Método que adiciona o curral
		public function addFreestall():void {
			_freestall = Farm.getFreestall();
			_lyr_sprites.add(_freestall);
		}
		
		// Método que adiciona a esterqueira
		public function addMidden():void {
			_midden = Farm.getMidden();
			_lyr_sprites.add(_midden);
		}
		
		// Gera um número randômico em um intervalo
		protected function randRange(minNum:Number, maxNum:Number):Number {
			return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
		}
	}
}